package sfs

import (
	"bytes"
	"compress/zlib"
	"encoding/binary"
	"github.com/valyala/bytebufferpool"
	"io"
	"wzgames/pkg/utils/byteutil"
)

type XWriter struct {
	bb *bytebufferpool.ByteBuffer
}

func (w *XWriter) Len() int {
	if w.bb != nil {
		return w.bb.Len()
	}

	return 0
}

func (w *XWriter) Write(p []byte) (int, error) {
	if w.bb == nil {
		w.bb = bytebufferpool.Get()
	}

	return w.bb.Write(p)
}

func (w *XWriter) WriteBool(x bool) error {
	var b uint8
	if x {
		b = 1
	} else {
		b = 0
	}
	return w.write(b)
}

func (w *XWriter) WriteByte(x int8) error {
	return w.write(x)
}

func (w *XWriter) WriteUByte(x uint8) error {
	return w.write(x)
}

func (w *XWriter) write(x interface{}) error {
	return binary.Write(w, binary.BigEndian, x)
}

func (w *XWriter) WriteShort(x int16) error {
	return w.write(x)
}

func (w *XWriter) WriteUShort(x uint16) error {
	return w.write(x)
}

func (w *XWriter) WriteUTF(x string) error {
	if err := w.WriteShort(int16(len(x))); err != nil {
		return err
	}
	return w.write(byteutil.StringToSliceByte(x))
}

func (w *XWriter) WriteInt(x int32) error {
	return w.write(x)
}

func (w *XWriter) WriteUInt(x uint32) error {
	return w.write(x)
}

func (w *XWriter) WriteLong(x int64) error {
	return w.write(x)
}

func (w *XWriter) WriteULong(x uint64) error {
	return w.write(x)
}

func (w *XWriter) WriteFloat(x float32) error {
	return w.write(x)
}

func (w *XWriter) WriteDouble(x float64) error {
	return w.write(x)
}

func (w *XWriter) WriteBytes(x []byte) error {
	return w.write(x)
}

func (w *XWriter) Compress() {
	var in bytes.Buffer
	zlibw := zlib.NewWriter(&in)
	w.WriteTo(zlibw)
	zlibw.Close()
	w.bb.Reset()
	in.WriteTo(w)
}

func (w *XWriter) Data() []byte {
	if w.bb != nil {
		return w.bb.Bytes()
	}

	return []byte{}
}

func (w *XWriter) WriteTo(wt io.Writer) (int64, error) {
	return w.bb.WriteTo(wt)
}

func (w *XWriter) Reset() {
	if w.bb != nil {
		bytebufferpool.Put(w.bb)
		w.bb = nil
	}
}

func (w *XWriter) WriteBoolS(key string, val bool) {
	w.WriteUTF(key)
	w.WriteUByte(Bool)
	w.WriteBool(val)
}

func (w *XWriter) WriteShortS(key string, val int16) {
	w.WriteUTF(key)
	w.WriteUByte(Short)
	w.WriteShort(val)
}

func (w *XWriter) WriteIntS(key string, val int32) {
	w.WriteUTF(key)
	w.WriteUByte(Int)
	w.WriteInt(val)
}

func (w *XWriter) WriteIntArrayS(key string, vals []int32) {
	w.WriteUTF(key)
	w.WriteUByte(IntArray)
	w.WriteUShort(uint16(len(vals)))
	for _, v := range vals {
		w.WriteInt(v)
	}
}

func (w *XWriter) WriteStringS(key, val string) {
	w.WriteUTF(key)
	w.WriteUByte(UtfString)
	w.WriteUTF(val)
}

func (w *XWriter) WriteUtfStringArray(key string, val []string) {
	w.WriteUTF(key)
	w.WriteUByte(UtfStringArray)
	w.WriteUShort(uint16(len(val)))
	for _, v := range val {
		w.WriteUTF(v)
	}
}

func (w *XWriter) WriteLongS(key string, val int64) {
	w.WriteUTF(key)
	w.WriteUByte(Long)
	w.WriteLong(val)
}

func (w *XWriter) WriteLongArrayS(key string, vals []int64) {
	w.WriteUTF(key)
	w.WriteUByte(LongArray)
	w.WriteUShort(uint16(len(vals)))
	for _, v := range vals {
		w.WriteLong(v)
	}
}

func (w *XWriter) WriteDoubleS(key string, val float64) {
	w.WriteUTF(key)
	w.WriteUByte(Double)
	w.WriteDouble(val)
}

func (w *XWriter) WriteDoubleArrayS(key string, vals []float64) {
	w.WriteUTF(key)
	w.WriteUByte(DoubleArray)
	w.WriteUShort(uint16(len(vals)))
	for _, v := range vals {
		w.WriteDouble(v)
	}
}

func (w *XWriter) WriteSfsObjectPre(key string, l uint16) {
	w.WriteUTF(key)
	w.WriteUByte(SfsObject)
	w.WriteUShort(l)
}

func (w *XWriter) WriteSfsArrayPre(key string, l uint16) {
	w.WriteUTF(key)
	w.WriteUByte(SfsArray)
	w.WriteUShort(l)
}
